<?php
// $Id$

/**
 * @file
 * Include file for the FriendFeed API OAuth module.
 *
 * Contains helper functions and negotiation callbacks for authenticating
 * with FriendFeed via OAuth.
 */

// Load FriendFeed OAuth utility functions
module_load_include('inc', 'friendfeed_oauth', 'includes/util');

function friendfeed_oauth_request() {
  $request_token_url  = variable_get('friendfeed_oauth_request_token_url', 'https://friendfeed.com/account/oauth/request_token');
  $authorize_url      = variable_get('friendfeed_oauth_authorize_url', 'https://friendfeed.com/account/oauth/authorize');

  $response  = friendfeed_oauth_signed_request($request_token_url, 'GET');

  if (is_array($response) && $response['code'] == 200) {
    // Generate an array for the unathorized tokens
    $unauthorized_tokens = _friendfeed_api_parse_query($response['string']);

    // We need the OAuth token secret for later in the handshake process
    // so we need to hold onto it.
    $_SESSION['oauth_token_secret'] = $unauthorized_tokens['oauth_token_secret'];

    // Now that we have the OAuth token, we can finally get the user to grant
    // access on Friendfeed.
    Header('Location: ' . $authorize_url . '?oauth_token=' . $unauthorized_tokens['oauth_token']);
  }
  else {
    drupal_set_message(t('There was a problem.<br>Response Code: %response_code<br>Response String: %response_string', array('%response_code' => $response['code'], '%response_string' => $response['string'])), 'error');
    return '';
  }
}

function friendfeed_oauth_authorize() {
  // Load up the user.
  global $user;

  // At this point, FriendFeed should be sending back an authorized OAuth token.
  // Take that authorized token and exchange it for an access token.
  $access_token_url = variable_get('friendfeed_oauth_access_token_url', 'https://friendfeed.com/account/oauth/access_token');

  $token = array(
    'key'     => $_GET['oauth_token'],
    'secret'  => $_SESSION['oauth_token_secret'],
  );

  $response = friendfeed_oauth_signed_request($access_token_url, 'GET', $token);
  
  if (is_array($response) && $response['code'] == 200) {
    // FriendFeed provides a response containing the access token, a token
    // secret, and the username. Parse the response and insert it into the
    // database.
    $access_info = _friendfeed_api_parse_query($response['string']);
    
    // Create a record and add it to the access token table.
    $table  = 'friendfeed_oauth_access_tokens';
    $record = new stdClass();
    
    $record->uid          = $user->uid;
    $record->access_token = $access_info['oauth_token'];
    $record->token_secret = $access_info['oauth_token_secret'];
    $record->username     = $access_info['username'];
    
    // Drop all records related to the user ID. Like the Highlander,
    // there can be only one FriendFeed account per user.
    db_query("DELETE FROM {$table} WHERE uid = %s", $record->uid);
    
    // Add the new record.
    drupal_write_record($table, $record);

    // Get the callback URL and redirect to that page.
    $destination = variable_get('friendfeed_oauth_callback_url', '<front>');
    drupal_goto($destination, NULL, NULL, 301);   
  }
  else {
    drupal_set_message(t('There was a problem.<br>Response Code: %response_code<br>Response String: %response_string', array('%response_code' => $response['code'], '%response_string' => $response['string'])), 'error');
    return t('Could not continue.');
  }
}

/**
 * Executes a signed request.
 *
 * @param $url
 *   The request URL.
 * @param $request_method
 *   Method by whch to request $url. Can be either GET or POST.
 * @param $token
 *   The access token, if it exists.
 * @param $parameters
 *   Parameters to use in the request.
 * @return
 *   The response from the request URL if successful, FALSE otherwise.
 */
function friendfeed_oauth_signed_request($url, $request_method = 'GET', $token = NULL, $parameters = NULL) {
  // Check to see if the OAuth module is ready. 
  if (!variable_get('friendfeed_oauth_ready', FALSE)) {
    drupal_set_message(t('The FriendFeed OAuth module is not properly configured. Check the <a href="@status">status report</a> for more information.', array('@status' => url('admin/reports/status'))), 'error');
    return FALSE;  
  }

  // Check $token because it needs to be in a specific format.
  if (!_friendfeed_oauth_check_token($token)) {
    drupal_set_message(t('FriendFeed OAuth: the request token is malformed.'), 'error');
    return FALSE;
  }

  // Load the OAuth library and FriendFeed API utility functions
  module_load_include('php', 'friendfeed_oauth', 'oauth/OAuth');
  module_load_include('inc', 'friendfeed_api', 'includes/util');

  // Get all the OAuth information from the settings. We copy them to prevent
  // changes during the handshake process and for readability.
  $consumer_key       = variable_get('friendfeed_oauth_consumer_key', '');
  $consumer_secret    = variable_get('friendfeed_oauth_consumer_secret', '');

  // Generate the signature method object. There are only three valid
  // choices: HMAC-SHA1, RSA-SHA1, and PLAINTEXT. Default is HMAC-SHA1.
  switch (variable_get('friendfeed_oauth_signature_method', 'HMAC-SHA1')) {
    case 'RSA-SHA1':
      $signature_method = new OAuthSignatureMethod_RSA_SHA1();
      break;
    case 'PLAINTEXT':
      $signature_method = new OAuthSignatureMethod_PLAINTEXT();
      break;
    case 'HMAC-SHA1':
    default:
      $signature_method = new OAuthSignatureMethod_HMAC_SHA1();
      break;
  }

  // Create OAuth consumer objects for the consumer key/secret and
  // if it exists, the access token.
  $consumer = new OAuthConsumer($consumer_key, $consumer_secret);

  if ($token != NULL) {
    $token = new OAuthConsumer($token['key'], $token['secret']);
  }

  // Create and sign the request.
  $request = OAuthRequest::from_consumer_and_token($consumer, $token, $request_method, $url, $parameters);
  $request->sign_request($signature_method, $consumer, $token);
  
  // Execute the request and return the response.
  if ($request_method == 'POST') {
    return _friendfeed_api_http_request($request, $parameters);  
  }
  else {
    return _friendfeed_api_http_request($request, NULL);  
  }
}

/**
 * Looks up a user's access token (if available).
 *
 * @param $uid
 *   The user's ID.
 * @return
 *   An array containing the user's access token and access token secret.
 */
function friendfeed_oauth_access_token($uid = NULL) {
  // Load up the user.
  global $user;
  
  $token = FALSE;

  $sql = 'SELECT access_token, token_secret FROM {friendfeed_oauth_access_tokens} WHERE uid = %d';
  if ($access_token_row = db_fetch_object(db_query($sql, $user->uid))) {
    $token = array(
      'key'     => $access_token_row->access_token,
      'secret'  => $access_token_row->token_secret,
    );
  }  
  
  return $token;
}